// Copyright (c) Microsoft Corporation.  All rights reserved.

#include "StdAfx.h"
#include "EventRecord.h"
#include "EventFile.h"
#include "EventEnumerator.h"

namespace Microsoft { namespace Samples { namespace SqlServer { namespace SSIS { namespace EventLogSource {

	EventEnumerator::EventEnumerator(EventFile^ eventFile) : bytesRead(0), buffer(NULL), bufferSize(0), eventFile(eventFile), flags(FORWARD_READ) {
		EnsureBuffer(180);
		this->record = gcnew EventRecord();
	}

	EventEnumerator::!EventEnumerator() {
		ReleaseBuffer();
	}

	void EventEnumerator::ReleaseBuffer() {
		if(this->buffer != NULL) {
			delete [] this->buffer;
			this->buffer = NULL;
		}
		this->bufferSize = 0;
	}

	void EventEnumerator::EnsureBuffer(DWORD size) {
		ReleaseBuffer();
		this->buffer = new BYTE[size];
		this->bufferSize = size;
	}

	bool EventEnumerator::MoveNext() {
		BOOL retry = false;
		DWORD lastError = ERROR_SUCCESS;

		if(this->bytesRead > 0) {
			this->logRecord = (PEVENTLOGRECORD)((PBYTE)this->logRecord + this->logRecord->Length);
		}
		else {
			// Read a group of events from the log
			DWORD bytesRead = 0;

			do {
				retry = false;
				DWORD bytesRequired = 0;
				BOOL retVal = ReadEventLog(
					this->eventFile->LogHandle, this->flags, 
					0, this->buffer, this->bufferSize, &bytesRead, &bytesRequired
					);
				if(!retVal) {
					lastError = GetLastError();
					if(lastError == ERROR_INSUFFICIENT_BUFFER) {
						EnsureBuffer(bytesRequired);
						retry = true;
					}
					else {
						if(lastError != ERROR_HANDLE_EOF) {
							throw gcnew System::ComponentModel::Win32Exception(lastError);
						}

						return false;
					}
				}

				if(this->flags == RESTART_READ) {
					this->flags = FORWARD_READ;
				}
			} while(retry);

			this->logRecord = (PEVENTLOGRECORD)this->buffer;
			this->bytesRead = bytesRead;
		}

		this->record->Initialize(logRecord);
		this->bytesRead -= this->logRecord->Length;

		return true;
	}

	void EventEnumerator::DebugRead() {
		this->record->ToString();
	}
} } } } }